import Image
cover = Image.open("input/badcat.png")
message = open("input/twitter.png", "rb").read()
dest = "output/alusprogrammi_tulemus"
dest_message = "output/message_valja"



def encode_imdata(imdata, data):
    '''given a sequence of pixels, returns an iterator of pixels with
    encoded data'''
    #print data
    datalen = len(data)
    if datalen == 0:
        raise ValueError('data is empty')
    if datalen * 3 > len(imdata):
        raise ValueError('data is too large for image')

    imdata = iter(imdata)
    result = []
    for i in xrange(datalen):
        x,y,z = imdata.next(),imdata.next(), imdata.next()
        pixels = [value & ~1 for value in
                x[:3]+y[:3]+z[:3]]            
        byte = ord(data[i])
        for j in xrange(7, -1, -1):
            pixels[j] |= byte & 1
            byte >>= 1
        if i == datalen - 1:
            pixels[-1] |= 1
        pixels = tuple(pixels)
        result.append(pixels[0:3])
        result.append(pixels[3:6])
        result.append(pixels[6:9])
        
    return result


def encode_inplace(image, data):
    '''hides data in an image'''

    w = image.size[0]
    (x, y) = (0, 0)
    for pixel in encode_imdata(image.getdata(), data):
        image.putpixel((x, y), pixel)
        if x == w - 1:
            x = 0
            y += 1
        else:
            x += 1


def extract(imdata):
    '''Given a sequence of pixels, returns an iterator of characters
    encoded in the image'''

    imdata = iter(imdata)
    while True:
        pixels = list(imdata.next()[:3] + imdata.next()[:3] + imdata.next()[:3])
        byte = 0
        for c in xrange(7):
            byte |= pixels[c] & 1
            byte <<= 1
        byte |= pixels[7] & 1
        yield chr(byte)
        if pixels[-1] & 1:
            break

def decode(image):
    '''extracts data from an image'''

    return ''.join(extract(image.getdata()))

encode_inplace(cover, message)
cover.save(dest+"."+cover.format, cover.format)
output = open(dest_message+"."+cover.format, "wb")
output.write(decode(cover))
output.close()


